package customview.ike.com.customviewproject.widget.Refresh1;

import android.content.Context;
import android.os.Build;
import android.support.annotation.Nullable;

import android.support.v4.view.ViewCompat;
import android.support.v4.widget.SwipeRefreshLayout;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.Scroller;
import android.widget.TextView;

import customview.ike.com.customviewproject.utils.DensityUtil;

/**
 * @author:ike
 * @function: 刷新加载更多的组件
 * @creat time:16:09 2017/11/23
 **/

public class PullToRefreshLayout extends LinearLayout {
    private Scroller mScroller;
    private ViewConfiguration configuration;
    private int scaledTouchSlop;
    private RelativeLayout headLayout;
    private RelativeLayout footerLayout;
    private int headerHeight;
    private int footHeight;
    private ListView contentView;
    private float mLastX;
    private float mLastY;
    private String Tag = "PullToRefreshLayout";
    private HeaderStatus curr_status = HeaderStatus.IDLE;
    private ScrollDirection direction;
    private TextView footerTv;
    private android.os.Handler handler = new android.os.Handler();
    /**
     * 如果下拉刷新长时间结果未返回，并且用户手动滑动隐藏头不觉，则认为取消本次刷新
     */
    /**
     * 是否刷新头隐藏
     */
    private boolean isHideTop;
    /**
     * 是否尾部刷新布局隐藏
     */
    private boolean isHideFooter;
    /**
     * 中间的内容view
     */
    private PullAbleView mPullAbleView;
    /**
     * 下拉刷新头
     */
    private RefreshHeader refreshHeader;
    /**
     * 加载更多尾布局
     */
    private RefreshFooter refreshFooter;
    /**
     * 是否是内部的孩子在滚动
     */
    private boolean isChildScroll;
    /**
     * 是否是刷新
     */
    private boolean isRefresh;
    /**
     * 是否是加载更多
     */
    private boolean isLoadMore;
    /**
     * 无效手指
     */
    private int INVALID_POINTER = -1;

    public enum HeaderStatus {
        /**
         * 空闲状态
         */
        IDLE,
        /**
         * 下拉刷新
         */
        PULL_TO_REFRESH,
        /**
         * 放手刷新
         */
        RELEASE_TO_REFRESH,
        /**
         * 刷新中
         */
        REFRESHING,
        /**
         * 刷新成功
         */
        REFRESH_COMPLETE,
        /**
         * 下拉刷新
         */
        REFRESH,
        /**
         * 加载更多
         */
        LOADMORE
    }

    /**
     * 滑动方向
     */
    public enum ScrollDirection {
        /**
         * 手势向上滑
         */
        UP,
        /**
         * 手势向上滑
         */
        DOWN
    }

    public PullToRefreshLayout(Context context) {
        this(context, null);
    }

    public PullToRefreshLayout(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public PullToRefreshLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setOrientation(VERTICAL);
    }

    private void init() {
        mScroller = new Scroller(getContext());
        configuration = ViewConfiguration.get(getContext());
        scaledTouchSlop = configuration.getScaledTouchSlop();
        addView(refreshHeader.getContentView(), 0);
        addView(refreshFooter.getContentView(), 2);
        int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            View child = getChildAt(i);
            if (child instanceof PullAbleView) {
                mPullAbleView = (PullAbleView) child;
            }
        }
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        headerHeight = refreshHeader.getContentViewHeight();
        footHeight = refreshFooter.getContentViewHeight();
    }

    @Override
    protected void onAttachedToWindow() {
        init();
        super.onAttachedToWindow();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        if (mPullAbleView != null) {
            ViewGroup.LayoutParams layoutParams = ((View) mPullAbleView).getLayoutParams();
            layoutParams.height = heightSize;
            ((View) mPullAbleView).setLayoutParams(layoutParams);
        }
        heightMeasureSpec = MeasureSpec.makeMeasureSpec(heightSize
                + refreshHeader.getContentViewHeight()
                + refreshFooter.getContentViewHeight(), MeasureSpec.EXACTLY);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        if (refreshHeader != null) {
            ((View) refreshHeader).layout(0, -refreshHeader.getContentViewHeight(), getWidth(), 0);
        }
        if (mPullAbleView != null) {
            ((View) mPullAbleView).layout(0, 0, getWidth(), getHeight() - refreshHeader.getContentViewHeight() - refreshFooter.getContentViewHeight());
        }
        if (refreshFooter != null) {
            ((View) refreshFooter).layout(0, getHeight() - refreshHeader.getContentViewHeight() - refreshFooter.getContentViewHeight(), getWidth(),
                    getHeight());
        }
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        int action = event.getActionMasked();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                activePointerId = event.getPointerId(0);
                try {
                    mLastY = event.getY(0);
                    mLastY = event.getY(0);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                if (!mScroller.isFinished()) {
                    mScroller.abortAnimation();
                }
                break;
            case MotionEvent.ACTION_MOVE:
                try {
                    if (activePointerId == INVALID_POINTER) {
                        int actionIndex_move = event.getActionIndex();
                        activePointerId = event.getPointerId(actionIndex_move);
                    }
                    int pointerIndex = event.findPointerIndex(activePointerId);
                    float dy = event.getY(pointerIndex) - mLastY;
                    if (dy > 0) {
                        direction = ScrollDirection.DOWN;
                    } else {
                        direction = ScrollDirection.UP;
                    }
                    //（手指为离开过屏幕）如果向下滑动并且
                    if (dy > 0 && hasDispatchToChild && isDraging && mPullAbleView.canPullDown()) {
                        //分发事件由listview滑动
                        isDraging = true;
                        hasDispatchToChild = false;
                        event.setAction(MotionEvent.ACTION_CANCEL);
                        dispatchTouchEvent(event);
                        event.setAction(MotionEvent.ACTION_DOWN);
                        return dispatchTouchEvent(event);
                        //内部滑动view滑到底部
                    } else if (dy < 0 && hasDispatchToChild && isDraging && mPullAbleView.canPullUp()) {
                        //分发事件由listview滑动
                        isDraging = true;
                        hasDispatchToChild = false;
                        event.setAction(MotionEvent.ACTION_CANCEL);
                        dispatchTouchEvent(event);
                        event.setAction(MotionEvent.ACTION_DOWN);
                        return dispatchTouchEvent(event);
                    } else if (dy > 0 && mPullAbleView.canPullDown() && isChildScroll) {
                        event.setAction(MotionEvent.ACTION_CANCEL);
                        dispatchTouchEvent(event);
                        event.setAction(MotionEvent.ACTION_DOWN);
                        return dispatchTouchEvent(event);
                    } else if (dy < 0 && mPullAbleView.canPullUp() && isChildScroll) {
                        event.setAction(MotionEvent.ACTION_CANCEL);
                        dispatchTouchEvent(event);
                        event.setAction(MotionEvent.ACTION_DOWN);
                        return dispatchTouchEvent(event);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }

                break;
            case MotionEvent.ACTION_CANCEL:
                isChildScroll = false;
                hasDispatchToChild = false;
                isDraging = false;
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                //处理多指触控将下落下拉的领外一根手指作为有效手指
                int actionIndex = event.getActionIndex();
                activePointerId = event.getPointerId(actionIndex);
                break;
            case MotionEvent.ACTION_UP:
                if (curr_status != HeaderStatus.REFRESHING) {
                    //回弹动画滚动回到开始的位置
                    startReturnToTopAnimator(-getScrollY());
                }
                activePointerId = INVALID_POINTER;
                isChildScroll = false;
                hasDispatchToChild = false;
                isDraging = false;
            default:
                break;
        }
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        int action = event.getActionMasked();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                break;
            case MotionEvent.ACTION_MOVE:
                try {
                    if (activePointerId == INVALID_POINTER) {
                        int actionIndex_move = event.getActionIndex();
                        activePointerId = event.getPointerId(actionIndex_move);
                    }
                    int pointerIndex = event.findPointerIndex(activePointerId);
                    float dx = event.getX(pointerIndex) - mLastX;
                    float dy = event.getY(pointerIndex) - mLastY;
                    mLastX = event.getX(pointerIndex);
                    mLastY = event.getY(pointerIndex);

                    //下拉刷新,下拉头未显示的时候
                    if (dy > 0 &&
                            dy >= scaledTouchSlop &&
                            Math.abs(dy) > Math.abs(dx) &&
                            mPullAbleView.canPullDown()) {
                        setRefreshOrLoadMore(HeaderStatus.REFRESH);
                        isDraging = true;
                        return true;
                    } else if (dy < 0 && //正在刷新且控件向上滑动
                            getScrollX() < 0 &&
                            mPullAbleView.canPullDown()) {
                        isDraging = true;
                        return true;
                    } else if (dy < 0 && //listview化到底部，并且向上进行拉动操作，拦截事件
                            Math.abs(dy) >= scaledTouchSlop &&
                            Math.abs(dy) > Math.abs(dx) &&
                            mPullAbleView.canPullUp()) {
                        setRefreshOrLoadMore(HeaderStatus.LOADMORE);
                        isDraging = true;
                        return true;
                    } else if (dy > 0 && getScrollY() > 0 &&  //listview化到底部，并且正在加载跟多的时候并且向下进行滑动操作，拦截事件
                            mPullAbleView.canPullUp()) {
                        isDraging = true;
                        return true;
                    } else if ((dy > 0 || dy < 0) && curr_status == HeaderStatus.REFRESHING) {
                        isDraging = true;
                        return true;
                    }
                    if (Math.abs(dy) > scaledTouchSlop) {
                        isChildScroll = true;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                break;
           
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:

                hasDispatchToChild = false;
                isDraging = false;
                break;
            default:
                break;
        }

        return super.onInterceptTouchEvent(event);
    }

    private boolean hasDispatchToChild;
    private boolean isDraging;
    //有效触摸手指的id
    private int activePointerId;
    //多指触控时离开屏幕的手指id
    private int pointerIdLeave;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getActionMasked();
        switch (action) {
            case MotionEvent.ACTION_DOWN:

                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                int actionIndex = event.getActionIndex();
             
                mLastY = event.getY(actionIndex);
                mLastX = event.getX(actionIndex);
                break;
            case MotionEvent.ACTION_MOVE:
                if (activePointerId == INVALID_POINTER) {
                    int actionIndex_move = event.getActionIndex();
                    activePointerId = event.getPointerId(actionIndex_move);
                }
                int pointerIndex = event.findPointerIndex(activePointerId);
                float dy = event.getY(pointerIndex) - mLastY;
                if (isDraging) {
                    scrollBy(0, (int) -dy / 2);
                    if (curr_status != HeaderStatus.REFRESHING) {
                        if (Math.abs(getScrollY()) < headerHeight || Math.abs(getScrollY()) < footHeight) {
                            changeRefreshStatus(HeaderStatus.PULL_TO_REFRESH);
                        } else {
                            changeRefreshStatus(HeaderStatus.RELEASE_TO_REFRESH);
                        }
                    }
                    //向下滑动（下拉）
                    if (dy > 0) {
                        //滑动事件由listView消费，la
                        //listView滑动到底部，并且此时向下滑动，父亲控件交还还滑动事件，由listview控件滑动
                        if (mPullAbleView.canPullUp() && isHideFooter) {
                            if (!hasDispatchToChild) {
                                hasDispatchToChild = true;
                                event.setAction(MotionEvent.ACTION_CANCEL);
                                onTouchEvent(event);
                                event.setAction(MotionEvent.ACTION_DOWN);
                                dispatchTouchEvent(event);
                                isChildScroll = true;
                            }
                        }
                    } else {
                        //刷新头有显示变为隐藏，并且手一直按在屏幕上，向上滑动，当刷新头刚好隐藏的时候，分发世间
                        //由listview滚动|
                        if (isHideTop && mPullAbleView.canPullDown()) {
                            if (!hasDispatchToChild) {
                                hasDispatchToChild = true;
                                isChildScroll = true;
                                event.setAction(MotionEvent.ACTION_CANCEL);
                                onTouchEvent(event);
                                event.setAction(MotionEvent.ACTION_DOWN);
                                dispatchTouchEvent(event);
                            }
                        }

                    }
                    mLastX = event.getX(pointerIndex);
                    mLastY = event.getY(pointerIndex);
                }

                break;
            case MotionEvent.ACTION_CANCEL:
                break;
            case MotionEvent.ACTION_POINTER_UP:
                int pointerIndexLeave = event.getActionIndex();
                pointerIdLeave = event.getPointerId(pointerIndexLeave);
                if (pointerIdLeave == activePointerId) {
                    //重新调整坐标
                    int reIndex = pointerIndexLeave == 0 ? 1 : 0;
                    //重新设置有效手指
                    activePointerId = event.findPointerIndex(reIndex);
                    mLastX = event.getX(reIndex);
                    mLastY = event.getY(reIndex);
                }
                break;
            case MotionEvent.ACTION_UP:
                hasDispatchToChild = false;
                isDraging = false;
                int scrollY = -getScrollY();
                if (curr_status != HeaderStatus.REFRESHING) {
                    if (getScrollY() <= -headerHeight) {
                        //头布局开始刷新
                        if (curr_status != HeaderStatus.REFRESHING) {
                            if (mListener != null) {
                                mListener.onRefresh();
                            }
                        }
                        changeRefreshStatus(HeaderStatus.REFRESHING);
                        startReturnToTopAnimator(scrollY - headerHeight);
                    } else if (getScrollY() >= footHeight) {
                        //尾布局开始刷新
                        if (curr_status != HeaderStatus.REFRESHING) {
                            if (mListener != null) {
                                mListener.onLoadMore();
                            }
                        }
                        changeRefreshStatus(HeaderStatus.REFRESHING);
                        startReturnToTopAnimator(footHeight - getScrollY());
                    } else {
                        //回弹动画滚动回到开始的位置
                        startReturnToTopAnimator(-getScrollY());
                    }
                } else {
                    //当前是下拉刷新中的状态时，用户下拉如果超过下拉头的高度，则控件回滚到下拉头完全显现的位置
                    //如果小于下拉头的高度则隐藏下拉头，后台刷新操作
                    if (getScrollY() <= -headerHeight) {
                        startReturnToTopAnimator(scrollY - headerHeight);
                    } else if (getScrollY() >= footHeight) {
                        //当前是加载跟多刷新中的状态时，用户上拉如果超过加载跟多头的高度，则控件回滚到加载跟布局完全显现的位置
                        startReturnToTopAnimator(footHeight - getScrollY());
                    } else {
                        //回弹动画滚动回到开始的位置
                        startReturnToTopAnimator(-getScrollY());
                    }
                }
                break;
            default:
                break;
        }
        return true;
    }

    /**
     * 改变刷新状态
     *
     * @param status
     */
    public void changeRefreshStatus(HeaderStatus status) {
        curr_status = status;
        if (isLoadMore) {
            refreshFooter.onStatusChanged(curr_status);
        } else if (isRefresh) {
            refreshHeader.onStatusChanged(curr_status);
        }
    }

    /**
     * 下拉刷新返回到顶部的动画
     */
    public void startReturnToTopAnimator(int scrollDistance) {
        if (!isDraging) {
            if (curr_status == HeaderStatus.REFRESHING) {
                //如果当前的刷新的状态，用户滑动刷新控件，使其隐藏的刷新头或者是加载尾，则认为是取消刷新或者是加载跟多
                if (Math.abs(getScrollY()) < headerHeight || Math.abs(getScrollY()) < footHeight) {
                    //取消加载跟多
                    if (getScrollY() > 0) {
                        if (mListener != null) {
                            mListener.cancelLoadMore();
                            changeRefreshStatus(HeaderStatus.IDLE);
                        }
                    } else {
                        //取消下拉刷新
                        if (mListener != null) {
                            mListener.cancelRefresh();
                            changeRefreshStatus(HeaderStatus.IDLE);
                        }
                    }
                }
            }
            mScroller.startScroll(0, getScrollY(), 0, scrollDistance);
            mScroller.computeScrollOffset();
            setRefreshOrLoadMore(HeaderStatus.IDLE);
        }

        invalidate();
    }

    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {
            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            invalidate();
        }
    }

    private RefreshListener mListener;

    /**
     * 暴露的刷新接口
     */
    public interface RefreshListener {
        /**
         * 下拉刷新接口
         */
        void onRefresh();

        /**
         * 加载更多的接口
         */
        void onLoadMore();

        /**
         * 取消刷新
         */
        void cancelRefresh();

        /**
         * 取消加载跟多
         */
        void cancelLoadMore();
    }

    public void setOnRefreshListener(RefreshListener mListener) {
        this.mListener = mListener;
    }

    /**
     * 刷新完成
     */
    public void onRefreshComplete() {
        startReturnToTopAnimator(-getScrollY());
        changeRefreshStatus(HeaderStatus.REFRESH_COMPLETE);
    }

    @Override
    public void scrollTo(int x, int y) {
        //判断头布局是否隐藏
        if (mPullAbleView.canPullDown()) {
            if (y >= 0) {
                y = 0;
            }
            isHideTop = y == 0;
        } else if (mPullAbleView.canPullUp()) {
            //判断尾布局是否隐藏
            if (y <= 0) {
                y = 0;
            }
            isHideFooter = y == 0;
        }
        super.scrollTo(x, y);
    }
    //////////////////////////////////////////////////////////////

    /**
     * 设置头布局
     *
     * @param header
     */
    public void setRefreshHeader(RefreshHeader header) {
        this.refreshHeader = header;

    }

    /**
     * 设置尾布局
     *
     * @param header
     */
    public void setRefreshFooter(RefreshFooter header) {
        this.refreshFooter = header;
    }

    /**
     * 设置是当前是刷新还是加载跟多
     *
     * @param status
     */
    private void setRefreshOrLoadMore(HeaderStatus status) {
        if (status == HeaderStatus.REFRESH) {
            this.isRefresh = true;
            this.isLoadMore = false;
        } else if (status == HeaderStatus.LOADMORE) {
            this.isRefresh = false;
            this.isLoadMore = true;
        } else if (status == HeaderStatus.IDLE) {
            this.isRefresh = false;
            this.isLoadMore = false;
        }
    }

    /**
     * 获取滑动方向
     *
     * @return
     */
    public ScrollDirection getScrollDirection() {
        return direction;
    }
    /**
     * 判断View是否可以继续上拉, false表示已经达到了最低端, 无法再继续上拉
     * @return canChildScrollDown
     */
    public boolean canChildScrollDown(View view) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
            if (view instanceof AbsListView) {
                final AbsListView absListView = (AbsListView) view;
                return absListView.getChildCount() > 0 && absListView.getAdapter() != null
                        && (absListView.getLastVisiblePosition() < absListView.getAdapter().getCount() - 1 || absListView.getChildAt(absListView.getChildCount() - 1)
                        .getBottom() < absListView.getPaddingBottom());
            } else {
                return ViewCompat.canScrollVertically(view, 1) || view.getScrollY() > 0;
            }
        } else {
            return ViewCompat.canScrollVertically(view, 1);
        }
    }
    /**
     * 判断ScrollView能否继续下拉, false表示已经到了最顶端, 无法继续下拉
     * @param view
     * @return
     */
    public boolean canChildScrollUp(View view) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
            if (view instanceof AbsListView) {
                final AbsListView absListView = (AbsListView) view;
                return absListView.getChildCount() > 0
                        && (absListView.getFirstVisiblePosition() > 0 || absListView.getChildAt(0)
                        .getTop() < absListView.getPaddingTop());
            } else {
                return ViewCompat.canScrollVertically(view, -1) || view.getScrollY() > 0;
            }
        } else {
            return ViewCompat.canScrollVertically(view, -1);
        }
    }

}
